package com.shooter.server;

import com.alibaba.fastjson.JSONObject;
import com.shooter.note.Action;
import com.shooter.utils.FileUtil;
import com.shooter.utils.PrintUtil;
import com.shooter.utils.upload.SmartUpload;
import com.shooter.utils.upload.SmartUploadException;
import com.shooter.utils.upload.UploadFile;
import org.apache.commons.codec.digest.DigestUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * Created by BLACK on 2018/3/27.
 */
public class BaseHttpServlet extends HttpServlet {
    public static final HashMap<String, Method> _CheckMethod = new HashMap<>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        req.setCharacterEncoding(ServerConfig.encoding);
        resp.setCharacterEncoding(ServerConfig.encoding);
        resp.setContentType("text/html;charset=" + ServerConfig.encoding);
        doHandle(new ServletDispose(req, resp));
    }

    protected void doHandle(ServletDispose dispose) {
        callEexecute(dispose);
    }

    //通过反射获取路径和方法中的 接口
    protected void callEexecute(ServletDispose dispose) {
        String[] s = dispose.getRequest().getPathInfo().split("/");
        String call = s[s.length - 1];
        String postfix = call.substring(call.indexOf(".") + 1, call.length());
        JSONObject jsonn = new JSONObject();
        jsonn.put(ServiceApi.CODE, ServiceApi.CODE_OK);
        if (postfix.equals("do")) {
            call = call.substring(0, call.indexOf("."));
            try {
                String mKey = this.getClass().getName() + call;
                //从缓存里面获取反射方法
                Method method = _CheckMethod.get(mKey);
                if (method != null) {
                    method.invoke(this, jsonn, dispose);
                    dispose.writerClient(jsonn.toJSONString());
                    return;
                } else {
                    for (int i = 0; i < this.getClass().getMethods().length; i++) {
                        //获取方法
                        method = this.getClass().getMethods()[i];
                        //获取方法名
                        String fun = method.getName();
                        //获取方法的Action备注
                        Annotation anno = method.getAnnotation(Action.class);
                        if (anno != null) {
                            if (fun.equals(call)) {
                                //缓存反射方法
                                _CheckMethod.put(mKey, method);
                                method.invoke(this, jsonn, dispose);
                                if (jsonn.get(ServiceApi.CODE) != null) {
                                    dispose.writerClient(jsonn.toJSONString());
                                }
                                return;
                            }
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                if (jsonn.get(ServiceApi.CODE) != null) {
                    dispose.writerClient(ServiceApi.CODE_NO, ServiceApi.ERROR_SERVER);
                }
                PrintUtil.printError(e);
                return;
            } catch (InvocationTargetException e) {
                if (jsonn.get(ServiceApi.CODE) != null) {
                    dispose.writerClient(ServiceApi.CODE_NO, ServiceApi.ERROR_SERVER);
                }
                PrintUtil.printError(e);
                return;
            }
        }
        dispose.writerClient(ServiceApi.CODE_NO, ServiceApi.ERROR_NO_PATH);
    }

    /**
     * 检测是否存在文件上传
     *
     * @param dispose
     * @param port_name 接口名
     * @return
     */
    protected String checkUploadType(ServletDispose dispose, String port_name) {
        return null;
    }

    /**
     * 上传文件操作
     *
     * @param dispose
     * @param maxSize  限制文件大小 / M/单位
     * @param fileType 限制上传类型/ jpg,png,gif
     */
    public void moreFileValueUpload(ServletDispose dispose, int maxSize, String fileType) {
        ArrayList<UploadFile> uploadFile = new ArrayList<>();
        //获取上传路径
        String path = getUploadingPath();
        FileUtil.createFilePath(path);
        SmartUpload su = new SmartUpload();
        try {
            su.initialize(getServletConfig(), dispose.getRequest(), dispose.getResponse());
            //设置上传文件大小
            su.setMaxFileSize(maxSize * 1024 * 1024);
            //设置所有文件的总大小
            su.setTotalMaxFileSize(maxSize * 1024 * 1024 * 10);
            //设置允许上传文件的类型
            su.setAllowedFilesList(fileType.toLowerCase());
            //开始接收上传文件到tomcat服务器
            su.upload();
            //将文件保存到 自定义上传路径下
            int fileSum = su.save(path);
            if (fileSum != 0) {
                //遍历查看上传的文件
                for (int i = 0; i < fileSum; i++) {
                    com.shooter.utils.upload.File tempFile = su.getFiles().getFile(i);
                    PrintUtil.printMsg("------------------------");
                    PrintUtil.printMsg("上传时填写的名字：" + tempFile.getFieldName());
                    PrintUtil.printMsg("上传文件长度:" + tempFile.getSize());
                    PrintUtil.printMsg("上传文件的拓展名：" + tempFile.getFileExt());
                    PrintUtil.printMsg("上传文件的全名：" + tempFile.getFilePathName());
                    PrintUtil.printMsg("------------------------");
                    //计算md5文件名
                    String fileName = DigestUtils.md5Hex(tempFile.getFilePathName() + tempFile.getSize() + System.currentTimeMillis()) + "." + tempFile.getFileExt();
                    tempFile.saveAs(path + fileName);
                    tempFile.setSavePathName(path + fileName);
                    FileUtil.deleteFile(path, tempFile.getFilePathName());
                    UploadFile uploadFile1 = new UploadFile();
                    uploadFile1.setFileName(fileName);
                    uploadFile1.setSize(tempFile.getSize());
                    uploadFile1.setFileType(tempFile.getFileExt());
                    uploadFile1.setFieldName(tempFile.getFieldName());
                    uploadFile1.setPathFileName(tempFile.getSavePathName());
                    uploadFile.add(uploadFile1);
                }
            }
            //配置流中参数
            dispose.setSmartUpload(su);
            //添加上传文件
            dispose.setUploadFile(uploadFile);
        } catch (ServletException e) {
            PrintUtil.printError(e);
            dispose.setUploadErrorInfo(ServiceApi.TEXT_00002);
        } catch (SmartUploadException e) {
            PrintUtil.printError(e);
            dispose.setUploadErrorInfo(ServiceApi.TEXT_00002);
        } catch (SecurityException e) {
            dispose.setUploadErrorInfo(String.format(ServiceApi.TEXT_00004, maxSize, fileType));
        } catch (NegativeArraySizeException e) {
            dispose.setUploadErrorInfo(ServiceApi.TEXT_00003);
        } catch (IOException e) {
            PrintUtil.printError(e);
            dispose.setUploadErrorInfo(ServiceApi.TEXT_00002);
        }
    }

    //获取项目相对路径
    protected String getRelativePath() {
        return getServletContext().getRealPath("/");
    }

    //获取上传目录
    protected String getUploadingPath() {
        return getRelativePath() + ServerConfig.uploadPath;
    }

    //删除所有上传文件
    protected void deleteAllUpFile(ArrayList<com.shooter.utils.upload.File> uploadFile) {
        if (uploadFile == null) return;
        for (int i = 0; i < uploadFile.size(); i++) {
            FileUtil.deleteFile(getRelativePath() + uploadFile.get(i).getSavePathName());
        }
    }

}
